package com.pai4j.user.service.relation;

import com.pai4j.common.enums.AccountRelationTypeEnum;
import com.pai4j.common.exception.BusinessException;
import com.pai4j.common.service.MinioService;
import com.pai4j.common.util.FreemarkerUtils;
import com.pai4j.common.util.ThreadPoolExecutorUtil;
import com.pai4j.domain.vo.request.CreateGroupRequestVO;
import com.pai4j.domain.vo.response.UploadResultVO;
import com.pai4j.domain.vo.response.UserBaseResponseInfoVO;
import com.pai4j.user.service.group.GroupMemberService;
import jakarta.transaction.Transactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.awt.image.BufferedImage;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
public class User2GroupAccountRelationService extends AbstractAccountRelationService {


    @Autowired
    private MinioService minioService;
    
    @Autowired
    private GroupMemberService groupMemberService;

    private static final String GROUP_PHOTO_TEMPLATE = "group_photo.ftl";

    @Override
    protected AccountRelationTypeEnum getRelationType() {

        return AccountRelationTypeEnum.USER_GROUP;
    }

    @Override
    protected boolean isAsyncDoAfterComplete() {

        return false;
    }

    @Override
    protected void doAfterComplete(Long id, String sourceAccount, String targetAccount, boolean subscribe) {
        // 添加群聊到用户账号关系列表
        if (subscribe) {
            super.init(targetAccount, sourceAccount);
            super.addTargetAccountRelationListCache(targetAccount, sourceAccount);
            super.init(sourceAccount, targetAccount);
            super.addTargetAccountRelationListCache(sourceAccount, targetAccount);
            // 添加群聊到用户聊天对话列表缓存
            super.addTargetAccount2SourceLastChattingList(sourceAccount, targetAccount);
        } else {
            // 退群：从双方关系列表缓存中删除
            // 先删除用户->群
            super.init(sourceAccount, targetAccount);
            super.removeTargetAccountRelationListCache(sourceAccount, targetAccount);
            // 从用户最近会话列表移除该群
            super.removeTargetAccountFromSourceLastChattingList(sourceAccount, targetAccount);
            // 再删除群->用户（需要交换上下文以计算正确的关系类型）
            super.init(targetAccount, sourceAccount);
            super.removeTargetAccountRelationListCache(targetAccount, sourceAccount);
        }
    }


    /**
     * 创建群聊 - 采用分阶段强一致性策略
     * 
     * 第一阶段（强一致性）：创建群聊基础数据
     *   - 生成群信息（头像、昵称）
     *   - 创建群聊记录到pai4j_user表
     *   - 创建群信息到pai4j_group_info表
     *   - 设置群主到pai4j_group_member表
     *   - 同步创建群主的账号关系到pai4j_account_relation表
     *   - 失败则整个事务回滚
     * 
     * 第二阶段（强一致性）：批量添加成员
     *   - 批量添加成员到pai4j_group_member表
     *   - 同步批量创建成员的账号关系到pai4j_account_relation表
     *   - 失败则整个事务回滚
     * 
     * 第三阶段（异步）：更新对话列表缓存
     *   - 异步通过MQ更新所有成员的对话列表
     *
     * @param requestVO
     * @return
     */
    @Transactional
    public String createChatGroup(CreateGroupRequestVO requestVO) {
        Set<String> groupUserIds = requestVO.getUserIds();
        // 添加当前创建人作为群成员
        groupUserIds.add(requestVO.getCreateUserId());
        List<String> groupUserIdList = new ArrayList<>(groupUserIds);
        
        log.info("开始创建群聊，创建人：{}，成员数：{}", requestVO.getCreateUserId(), groupUserIds.size());
        
        // ============ 第一阶段：创建群聊基础数据（强一致性） ============
        
        // 走redis批量查询群成员详情
        List<UserBaseResponseInfoVO> groupUsers = super.userService.batchGetUserListInfoFromCache(groupUserIdList);
        
        // 1. 生成群昵称：默认取前三个用户的昵称拼接
        String groupName = this.genGroupName(groupUsers);
        
        // 2. 生成群头像：取前9个用户头像合成一张新图片作为群头像
        String groupPhoto = this.genGroupPhoto(groupUsers);
        log.info("创建群聊生成头像: {}", groupPhoto);
        
        // 3. 创建群聊记录到pai4j_user表
        String groupId = userService.registerGroup2DB(groupName, groupPhoto, requestVO.getCreateUserId());
        log.info("群聊记录已创建到pai4j_user表，groupId={}", groupId);
        
        // 4. 创建群聊信息记录到pai4j_group_info表
        // 【强一致性】失败则抛出异常，触发事务回滚
        boolean groupInfoCreateSuccess = groupMemberService.createGroupInfoRecord(groupId, groupName, groupPhoto, requestVO.getCreateUserId());
        if (!groupInfoCreateSuccess) {
            log.error("创建群聊信息记录失败，事务将回滚：groupId={}", groupId);
            throw new BusinessException("创建群聊信息记录失败");
        }
        log.info("群聊信息记录已创建到pai4j_group_info表，groupId={}", groupId);
        
        // 5. 设置创建者为群主到pai4j_group_member表
        // 【强一致性】失败则抛出异常，触发事务回滚
        boolean ownerSetSuccess = groupMemberService.setGroupOwnerOnCreation(groupId, requestVO.getCreateUserId());
        if (!ownerSetSuccess) {
            log.error("设置群主失败，事务将回滚：groupId={}, ownerAccount={}", groupId, requestVO.getCreateUserId());
            throw new BusinessException("设置群主失败");
        }
        log.info("群主已设置到pai4j_group_member表，groupId={}, ownerAccount={}", groupId, requestVO.getCreateUserId());
        
        // 6. 同步创建群主的账号关系到pai4j_account_relation表
        // 【强一致性】失败则抛出异常，触发事务回滚
        super.subscribe(requestVO.getCreateUserId(), groupId);
        log.info("群主账号关系已同步到pai4j_account_relation表，ownerAccount={}, groupId={}", requestVO.getCreateUserId(), groupId);
        
        // ============ 第二阶段：批量添加成员（强一致性） ============
        
        // 7. 批量添加其他群成员到pai4j_group_member表和pai4j_account_relation表
        List<String> otherMembers = groupUserIdList.stream()
                .filter(uid -> !uid.equals(requestVO.getCreateUserId()))
                .collect(Collectors.toList());
        
        if (!otherMembers.isEmpty()) {
            // 7.1 批量添加成员到pai4j_group_member表
            // 【强一致性】失败则抛出异常，触发事务回滚
            boolean membersAddSuccess = groupMemberService.batchAddMembersOnCreation(groupId, otherMembers, requestVO.getCreateUserId());
            if (!membersAddSuccess) {
                log.error("批量添加群成员失败，事务将回滚：groupId={}, members={}", groupId, otherMembers);
                throw new BusinessException("批量添加群成员失败");
            }
            log.info("群成员已批量添加到pai4j_group_member表，groupId={}, 成员数={}", groupId, otherMembers.size());
            
            // 7.2 批量同步创建成员的账号关系到pai4j_account_relation表
            // 【强一致性】失败则抛出异常，触发整个事务回滚
            for (String memberAccount : otherMembers) {
                try {
                    super.subscribe(memberAccount, groupId);
                    log.debug("成员账号关系已同步：memberAccount={}, groupId={}", memberAccount, groupId);
                } catch (Exception e) {
                    log.error("成员账号关系同步失败，事务将回滚：memberAccount={}, groupId={}", memberAccount, groupId, e);
                    throw new BusinessException("成员账号关系同步失败: " + memberAccount, e);
                }
            }
            log.info("所有成员账号关系已同步到pai4j_account_relation表，groupId={}, 成员数={}", groupId, otherMembers.size());
        }
        
        // ============ 第三阶段：异步更新对话列表缓存 ============
        
        // 8. 异步通过MQ通知刷新所有成员的对话列表
        // 注意：此阶段失败不影响群聊创建，可通过补偿机制修复
        ThreadPoolExecutorUtil.execute(() -> {
            groupUserIds.forEach(uid -> {
                try {
                    // 通过MQ通知刷新用户的最新对话列表（将群聊添加到对话列表头部）
                    super.addTargetAccount2SourceLastChattingList(uid, groupId);
                    log.debug("用户对话列表更新通知已发送：userAccount={}, groupId={}", uid, groupId);
                } catch (Exception e) {
                    log.error("用户对话列表更新通知发送失败（不影响群聊创建）：userAccount={}, groupId={}", uid, groupId, e);
                }
            });
        });
        
        log.info("群聊创建完成（强一致性保证）：groupId={}, 群主={}, 总成员数={}", 
                groupId, requestVO.getCreateUserId(), groupUserIds.size());
        log.info("数据同步情况：pai4j_user表✓, pai4j_group_info表✓, pai4j_group_member表✓, pai4j_account_relation表✓");
        
        return groupId;
    }

    /**
     * 群昵称：默认取前三个用户的昵称拼接
     * @param groupUsers
     * @return
     */
    private String genGroupName(List<UserBaseResponseInfoVO> groupUsers) {
        List<UserBaseResponseInfoVO> top3Users = groupUsers.subList(0, 2);
        StringBuilder sb = new StringBuilder();
        for (UserBaseResponseInfoVO u : top3Users) {
            sb.append(u.getUserName()).append("、");
        }
        return sb.toString().substring(0, sb.length() - 1);
    }

    /**
     * 合成群头像
     *
     * @param groupUsers
     * @return
     */
    private String genGroupPhoto(List<UserBaseResponseInfoVO> groupUsers) {

        // 1. 取前9个用户头像合成新图片
        List<UserBaseResponseInfoVO> top9Users = groupUsers.subList(0, Math.min(9, groupUsers.size()));
        List<String> photos = top9Users.stream().map(UserBaseResponseInfoVO::getPhoto).collect(Collectors.toList());
        // 合成图片
        Map<String, Object> vars = new HashMap<>();
        vars.put("photos", photos);
        BufferedImage bufferedImage;
        try {
            bufferedImage = FreemarkerUtils.turnImage(GROUP_PHOTO_TEMPLATE, vars, 300);
        } catch (Exception e) {
            log.error("创建群聊异常 =====> 头像生成失败.", e);
            throw new BusinessException("头像生成失败");
        }
        // 2. 头像上传OS
        UploadResultVO uploadResult = minioService.upload(bufferedImage);
        return uploadResult.getUrl();
    }
}
